package com.yxsk.relay.job.admin.core.schedule.quartz.vo;

import com.yxsk.relay.job.component.common.exception.RelayJobRuntimeException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.quartz.Job;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.text.MessageFormat;

/**
 * @Author 11376
 * @CreaTime 2019/6/5 13:55
 * @Description
 */
@Getter
@Setter
@ToString
public abstract class JobConfig {

    // 任务id
    private String id;
    // 任务组
    private String appName;
    // 任务名称
    private String handlerName;
    // cron表达式
    private String cron;
    // 执行超时时间
    private Long executeTimeout;
    // 失败重试次数
    private Integer failRetryTimes;
    // 执行参数
    private String executeParam;
    // 执行模式
    private ExecuteModel executeModel;
    // 路由模式
    private RouteStrategy routeStrategy;
    // 阻塞策略
    private BlockStrategy blockStrategy;
    // 任务执行器
    private Class<? extends Job> scheduleTaskClass;
    // 任务状态
    private JobStatus status;

    @AllArgsConstructor
    @Getter
    public enum ExecuteModel {
        /**
         * 经典模式， 任务执行完成 -> 触发子任务
         */
        CLASSIC("CLASSIC", "经典模式"),
        /**
         * 流水线模式， 任务执行完成 -> 触发子任务，并且执行子任务的参数为任务执行完成结果
         */
        ASSEMBLY_LINE("ASSEMBLY-LINE", "流水线模式"),
        /**
         * 集群模式， 触发的任务全部执行完成 -> 触发子任务
         * 并且执行子任务的参数为该触发的任务结果集处理后的结果，
         * 任务结果处理器为端点处理器 Collectable
         */
        CLUSTER("CLUSTER", "集群模式");

        private String model;

        private String name;

        public static ExecuteModel getExecuteModel(String model) {
            if (StringUtils.hasLength(model)) {
                ExecuteModel[] values = ExecuteModel.values();
                for (ExecuteModel value : values) {
                    if (value.model.equals(model)) {
                        return value;
                    }
                }
            }
            throw new IllegalArgumentException("Not found execute model: " + model);
        }
    }

    @AllArgsConstructor
    @Getter
    public enum RouteStrategy {
        // 轮询
        POLL("POLL", "单机轮询"),
        // 多个执行端点
        MULTIPLE_INSTANCES("MULTIPLE_INSTANCES", "多任务实例");

        private String strategy;

        private String name;

        public static RouteStrategy getStrategy(String strategy) {
            if (StringUtils.hasLength(strategy)) {
                RouteStrategy[] values = RouteStrategy.values();
                for (RouteStrategy value : values) {
                    if (value.strategy.equals(strategy)) {
                        return value;
                    }
                }
            }
            throw new IllegalArgumentException("Not found route strategy: " + strategy);
        }
    }

    @AllArgsConstructor
    @Getter
    public enum BlockStrategy {
        /**
         * 串行, 等待上一次任务执行完成才触发
         */
        SERIAL("SERIAL", "串行策略"),
        /**
         * 无阻塞
         */
        NONE("NONE", "无阻塞");

        private String strategy;

        private String name;

        public static BlockStrategy getBlockStrategy(String strategy) {
            Assert.hasLength(strategy, "Block strategy not be null.");
            BlockStrategy[] values = BlockStrategy.values();
            for (BlockStrategy value : values) {
                if (value.strategy.equals(strategy)) {
                    return value;
                }
            }
            throw new RelayJobRuntimeException(MessageFormat.format("Not found [{0}] block strategy.", strategy));
        }

    }

    @AllArgsConstructor
    @Getter
    public enum JobStatus {
        // 正常
        NORMAL("NORMAL", "正常"),
        // 暂停
        PAUSE("PAUSE", "暂停"),
        // 废弃
        ABANDONED("ABANDONED", "废弃");

        private String status;

        private String name;

        public static JobStatus getJobStatus(String status) {
            Assert.hasLength(status, "Job status not be null");
            JobStatus[] values = JobStatus.values();
            for (JobStatus value : values) {
                if (value.status.equals(status)) {
                    return value;
                }
            }
            throw new RelayJobRuntimeException(MessageFormat.format("Not found [{0}] job status.", status));
        }
    }

}
